home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 003 / _microcosm / !Microcosm / c / Microcosm
Text File  |  1990-08-16  |  32KB  |  1,115 lines

  1. /***************************************************************************
  2.  *
  3.  *  Microcosm.c
  4.  *
  5.  *  Archimedes
  6.  *
  7.  *  Microcosm program  - Public Domain release
  8.  *  5 June 1990 : version 1
  9.  *
  10.  *   Written by....
  11.  *      Michael Spearpoint
  12.  *      3 Lawrence Crescent
  13.  *      Edgware
  14.  *      Middx  HA8 5PB
  15.  *
  16.  ***************************************************************************/
  17.  
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <math.h>
  21. #include <stdlib.h>
  22. #include <time.h>
  23.  
  24. #include "res.h"
  25. #include "resspr.h"
  26. #include "bbc.h"
  27.  
  28. /**************************************************************************/
  29. /* Define global variables and format of any functions */
  30.  
  31. #define VERSION  "version 1   "
  32.  
  33. #define GRAPHICS     TRUE   /* Draw creature graphics code */
  34. #define WRAP_AROUND  FALSE  /* Wrap around movement code   */
  35.  
  36. /* Define screen plotting factors */
  37. #define SCREEN_X   22       /* Screen plotting x factor       */
  38. #define SCREEN_Y   22       /* Screen plotting y factor       */
  39. #define ORIGIN_X   10       /* Origin of graph - x coordinate */
  40. #define ORIGIN_Y  630       /* Origin of graph - y coordinate */
  41. #define WIDTH     900       /* Graph width                    */
  42.  
  43. #define DIRECTIONS  8       /* Area to check for food etc - set to 8 or 4
  44.                              * When 4 - checks n,e,s,w
  45.                              * When 8 - checks n,ne,nw,e,w,s,se,sw       */
  46.  
  47. #define X_MAX           55  /* Number of grid cells - x direction */
  48. #define Y_MAX           27  /* Number of grid cells - y direction */
  49. #define CREATURE_TYPES  10  /* Max number of creature types       */
  50. #define MAX_FOOD         4  /* Number of different creature types 
  51.                              * that a particular type can eat     */
  52.  
  53. #define MAX_CREATURES   (X_MAX * Y_MAX)
  54.  
  55. #define DEAD     0
  56. #define EMPTY    0
  57. #define FAIL    -1
  58.  
  59. #define RANDOM(A)      ((A + 1) * (float)rand() / (float)RAND_MAX)
  60.  
  61. /* Palette colours */
  62. enum { WHITE, GREY1, GREY2, GREY3, GREY4, GREY5, GREY6, BLACK,
  63.        BLUE, YELLOW, GREEN, RED, CREAM, DARK_GREEN, ORANGE, CYAN };
  64.  
  65. /**************************************************************************/
  66. /* Define procedures */
  67.  
  68. /* Initialisation procedures */
  69. void initialise(void);
  70. void create_populations(void);
  71. void draw_axes(void);
  72.  
  73. /* File reading procedures */
  74. BOOL load_file(void);
  75. void read_data(int);
  76. void read_general_data(void);
  77. void read_initial_positions(void);
  78.  
  79. /* Main processing procedures */
  80. void main_loop(void);
  81. void process_creatures(void);
  82. void update_graph(int);
  83.  
  84. /* Creature processing procedures */
  85. void move_creature(int, int);
  86. void consume_strength(int, int);
  87. void feed(int, int);
  88. void birth(int, int);
  89.  
  90. /* General routines */
  91. BOOL valid_location(char, char);
  92. int  find_creature_at(char, char);
  93. int  find_free_creature(void);
  94.  
  95. /**************************************************************************/
  96.  
  97. char        grid[X_MAX + 1][Y_MAX + 1] = EMPTY;
  98. int         pop_tots[CREATURE_TYPES + 1]     = 0;
  99. int         old_pop_tots[CREATURE_TYPES + 1] = 0;
  100. FILE        *read;
  101. sprite_area *sprite_bk;
  102.  
  103. /* Global data structure */
  104. struct global
  105.       {
  106.        int   iterations;
  107.        int   wait;
  108.        BOOL  random;
  109.        BOOL  draw_creatures;
  110.        BOOL  draw_overall;
  111.        int   total_types;
  112.        float graph_scale;
  113.       } global = { 0, 0, TRUE, TRUE, TRUE, 1, (float) 1 };
  114.  
  115. /* Creature type structure */
  116. struct type 
  117.       {
  118.        char  name[11];      /* Creature / sprite name                    */
  119.        int   initial_number;/* Initial number for random start           */
  120.        char  move;          /* Movement rate                             */
  121.        int   max_str;       /* Max strength for creature                 */
  122.        signed char consumption; /* Strength consumption per iteration    */
  123.        int   food;          /* Valid food types for this creature type   */
  124.        int   food_value;    /* Food value when creature is eaten         */
  125.        int   adult;         /* Age at which creature can give birth      */
  126.        int   birth_str;     /* Minimum strength for birth                */
  127.        char  child_str;     /* Percentage of parents strength to child   */
  128.        int   decay;         /* Creature type formed by the death of type */
  129.       } 
  130.        type[CREATURE_TYPES];
  131.  
  132. /* Individual creature */
  133. struct creature
  134.       {
  135.        char         type;   /* Creature type              */
  136.        char         x;      /* x coord                    */
  137.        char         y;      /* y coord                    */
  138.        signed char  dx;     /* Movement in x dir  +1,0,-1 */
  139.        signed char  dy;     /* Movement in y dir  +1,0,-1 */
  140.        int          str;    /* Current strength           */
  141.        char         move_c; /* Movement counter           */
  142.        int          age;    /* Age in iterations          */
  143.       }
  144.        creature[MAX_CREATURES + 1] =
  145.       {
  146.        0, 0, 0, 0, 0, 0, 0, 0
  147.       };      
  148.  
  149. #if DIRECTIONS == 8
  150. struct loc_offset
  151.        {
  152.         signed char  dx;
  153.         signed char  dy;
  154.        }
  155.        loc_offset[DIRECTIONS] =
  156.        { -1,-1, 0,-1, +1,-1, -1,0, +1,0, -1,+1, 0,+1, +1,+1 };
  157. #endif
  158.  
  159. #if DIRECTIONS == 4
  160. struct loc_offset
  161.        {
  162.         signed char  dx;
  163.         signed char  dy;
  164.        }
  165.        loc_offset[DIRECTIONS] =
  166.        { 0,-1, -1,0, +1,0, 0,+1, };
  167. #endif
  168.  
  169.  
  170. /**************************************************************************/
  171.  
  172.  
  173.  
  174. /**************************************************************************/
  175. /*             INITIALISATION AND FILE READING PROCEDURES                 */
  176. /**************************************************************************/
  177. /* Initialise */
  178.  
  179. void initialise(void)
  180.  
  181. {
  182.  res_init("Microcosm");      /* Find resources   */
  183.  resspr_init();              /* Find sprite file */
  184.  sprite_bk = resspr_area();
  185.  
  186.  /* Set up screen mode and load palette */
  187.  bbc_mode(12);
  188.  system("<Microcosm$Dir>.Palette");
  189.  bbc_colour(128 + BLACK);
  190.  bbc_colour(WHITE);
  191.  bbc_cls();
  192.  
  193.  /* Reseed randomiser */
  194.  srand(clock());
  195.  
  196.  
  197.  /* Start up message */
  198.  bbc_tab(22,8);
  199.  printf("Microcosm program (Public Domain)");
  200.  bbc_tab(26,10);
  201.  printf("%s",VERSION);
  202.  printf("%s",__DATE__);
  203.  bbc_tab(28,12);
  204.  printf("Michael Spearpoint");
  205.  bbc_tab(2,30);
  206.  printf("Press any key....");
  207.  bbc_get();
  208.  bbc_cls();
  209. }
  210.  
  211. /**************************************************************************/
  212. /* Load set up file */
  213.  
  214. BOOL load_file(void)
  215.  
  216. {
  217.  char  *file = "<Microcosm$Dir>.SetUp";
  218.  BOOL  comment = FALSE;
  219.  char  chr;
  220.  int   data_type;
  221.  
  222.  
  223.  read = fopen(file,"r");
  224.  
  225.  /* Found file ? */
  226.  if (read == NULL)
  227.     { 
  228.      printf("Error - SetUp file not found, program terminated");
  229.      return(FALSE);
  230.     }
  231.  
  232.  /* Read file down to # character */
  233.  while ((chr = fgetc(read)) != '#')
  234.        {
  235.         switch (chr)
  236.                {
  237.                 case '*' : comment = !comment;
  238.                            break;
  239.  
  240.                 case '}' : if (comment == FALSE)
  241.                               { read_general_data(); }
  242.                            break;
  243.  
  244.                 case '>' : if (comment == FALSE)
  245.                               {
  246.                                fscanf(read,"%i",&data_type);
  247.                                read_data(data_type);
  248.                               }
  249.                            break;
  250.  
  251.                 default :  break;
  252.                }
  253.         }
  254.  
  255.  fclose(read);
  256.  return(TRUE);
  257. }
  258.  
  259. /**************************************************************************/
  260. /* Read general data from file */
  261.  
  262. void read_general_data(void)
  263.  
  264. {
  265.  static int  count = 0;
  266.        char  chr;
  267.  
  268.  ++count;
  269.  
  270.  switch (count)
  271.         {
  272.          case 1 : fscanf(read,"%i", &global.total_types);
  273.                   if (global.total_types > CREATURE_TYPES)
  274.                      {
  275.                       printf("Error - Too many creature types");
  276.                       exit(NULL);
  277.                      }
  278.                   break;
  279.  
  280.          case 2 : fscanf(read,"%i", &global.iterations);
  281.                   break;
  282.  
  283.          case 3 : do {
  284.                       fscanf(read,"%c",&chr);
  285.                      } while (chr == ' ');
  286.                   global.random = (chr == 'Y') ? TRUE : FALSE;
  287.                   read_initial_positions();
  288.                   break;
  289.  
  290.          case 4 : fscanf(read,"%i",&global.wait);
  291.                   break;
  292.  
  293.          case 5 : fscanf(read,"%f",&global.graph_scale);
  294.                   break;
  295.  
  296.          case 6 : do {
  297.                       fscanf(read,"%c",&chr);
  298.                      } while (chr == ' '); 
  299.                   global.draw_creatures = (chr == 'Y') ? TRUE : FALSE;
  300.                   break;
  301.  
  302.          case 7 : do {
  303.                       fscanf(read,"%c",&chr);
  304.                      } while (chr == ' '); 
  305.                   global.draw_overall = (chr == 'Y') ? TRUE : FALSE;
  306.                   break;
  307.  
  308.          default : break;
  309.         }
  310. }
  311.  
  312. /**************************************************************************/
  313. /* Read the initial creature positions from the setup file */
  314.  
  315. void read_initial_positions(void)
  316.  
  317. {
  318.  int   x = -4, y = Y_MAX;
  319.  int   c_type;
  320.  char  chr;
  321.  
  322.  /* Random creature set up ? */
  323.  if (global.random == TRUE)
  324.     {
  325.      /* Search file for next '}' character */
  326.      while ((chr = fgetc(read)) != '}') { }
  327.      ungetc('}',read);
  328.     }
  329.     else
  330.     {
  331.      /* Find the '>' character which defines the beginning of the table */
  332.      while ((chr = fgetc(read)) != '>') { }
  333.  
  334.      while ((chr = fgetc(read)) != '*')
  335.            {
  336.             switch (chr)
  337.                    {
  338.                     /* Increment x coord */
  339.                     case ' '  : ++x;
  340.                                 break;
  341.  
  342.                     /* Next line of table - reset x and decrement y coords */
  343.                     case '\r' : 
  344.                     case '\n' : x = -4;  --y;
  345.                                 break;
  346.  
  347.                     /* Character found - check that it is valid */
  348.                     default : c_type = ((int) chr - 'a' + 1);
  349.                               if(c_type >= 0 && c_type <= global.total_types)
  350.                                 {
  351.                                  /* Position creature if the location
  352.                                   * is on the grid */
  353.                                  if (valid_location(x,y) == TRUE)
  354.                                     {  grid[x][y] = c_type; }
  355.                                 }
  356.                               ++x;
  357.                               break;
  358.                    }
  359.            }
  360.  
  361.      /* Put the '*' character back into the file buffer */
  362.      ungetc('*',read);
  363.  
  364.     }
  365. }
  366.  
  367. /**************************************************************************/
  368. /* Read data from the SetUp file */
  369.  
  370. void read_data(int data_type)
  371.  
  372. #define NAME         0
  373. #define INITIAL_NO   1
  374. #define MOVE         2
  375. #define MAX_STR      3
  376. #define CONSUMPTION  4
  377. #define FOOD_VALUE   5
  378. #define ADULT        6
  379. #define BIRTH_STR    7
  380. #define FOOD         8
  381. #define CHILD_STR    9
  382. #define DECAY       10
  383.  
  384. {
  385.  int  c, n;
  386.  int  c_type;
  387.  char chr;
  388.  
  389.  
  390.  switch (data_type)
  391.         {
  392.          case NAME       : for (c = 1; c <= global.total_types; c++)
  393.                                {
  394.                                 fscanf(read,"%s",type[c].name);
  395.                                 if (strlen(type[c].name) > 10)
  396.                                    {
  397.                                     printf("Error - Sprite name too long");
  398.                                     exit(NULL);
  399.                                    }
  400.                                }
  401.                            break;
  402.  
  403.  
  404.          case INITIAL_NO : for (c = 1; c <= global.total_types; c++)
  405.                                {
  406.                                 fscanf(read,"%i",&type[c].initial_number);
  407.                                }
  408.                            break;
  409.  
  410.  
  411.          case MOVE       : for (c = 1; c <= global.total_types; c++)
  412.                                {
  413.                                 fscanf(read,"%i",&type[c].move);
  414.                                 if (type[c].move < 0)
  415.                                   {
  416.                                    printf("Error - ");
  417.                                    printf("Movement rate must be 0 or more");
  418.                                    exit(NULL);
  419.                                   }
  420.                                }
  421.                            break;
  422.  
  423.  
  424.          case MAX_STR    : for (c = 1; c <= global.total_types; c++)
  425.                                {
  426.                                 fscanf(read,"%i",&type[c].max_str);
  427.                                 if (type[c].max_str < 1)
  428.                                   {
  429.                                    printf("Error - ");
  430.                                    printf("Max strength must be 1 or more");
  431.                                    exit(NULL);
  432.                                   }
  433.                                }
  434.                            break;
  435.  
  436.  
  437.          case CONSUMPTION : for (c = 1; c <= global.total_types; c++)
  438.                                {
  439.                                 fscanf(read,"%i",&type[c].consumption);
  440.                                }
  441.                            break;
  442.  
  443.  
  444.          case FOOD_VALUE : for (c = 1; c <= global.total_types; c++)
  445.                                {
  446.                                 fscanf(read,"%i",&type[c].food_value);
  447.                                }
  448.                            break;
  449.  
  450.  
  451.          case ADULT      : for (c = 1; c <= global.total_types; c++)
  452.                                {
  453.                                 fscanf(read,"%i",&type[c].adult);
  454.                                }
  455.                            break;
  456.  
  457.  
  458.          case BIRTH_STR  : for (c = 1; c <= global.total_types; c++)
  459.                                {
  460.                                 fscanf(read,"%i",&type[c].birth_str);
  461.                                }
  462.                            break;
  463.  
  464.  
  465.          case CHILD_STR  : for (c = 1; c <= global.total_types; c++)
  466.                                {
  467.                                 fscanf(read,"%i",&type[c].child_str);
  468.                                }
  469.                            break;
  470.  
  471.  
  472.          case DECAY      : for (c = 1; c <= global.total_types; c++)
  473.                                {
  474.                                 while ((chr = fgetc(read)) == ' ') { }
  475.                                 c_type = (int) chr - 'a' + 1;
  476.                                 if (c_type > 0 && c_type <= CREATURE_TYPES)
  477.                                    { type[c].decay = (char) c_type; }
  478.                                }
  479.                            break;
  480.  
  481.  
  482.          case FOOD       : for (c = 1; c <= global.total_types; c++)
  483.                                {
  484.                                 for(n = 0; n < MAX_FOOD; n++)
  485.                                    {
  486.                                    while ((chr = fgetc(read)) == ' ') { }
  487.                                    c_type = (int) chr - 'a' + 1;
  488.                                    if(c_type > 0 && c_type <= CREATURE_TYPES)
  489.                                      {
  490.                                      if(c_type != ('.' - 'a' + 1))
  491.                                        {type[c].food +=(int)(pow(2,c_type));}
  492.                                      }
  493.                                    }
  494.                                }
  495.                            break;
  496.  
  497.          default : break;
  498.         }
  499. }
  500.  
  501. /**************************************************************************/
  502. /* Create the initial creature populations */
  503.  
  504. void create_populations(void)
  505.  
  506. {
  507.  int        c_type, c, x, y;
  508.  int        number = 0;
  509.  sprite_id  id;
  510.  
  511.  
  512.  /* If random set up - fill grid */
  513.  if (global.random == TRUE)
  514.     {
  515.      for (c_type = 1; c_type <= global.total_types; c_type++)
  516.          {
  517.           for (c = 1; c <= type[c_type].initial_number; c++)
  518.               {
  519.                /* Find an empty location on the grid */
  520.                do {
  521.                    x = (int) RANDOM(X_MAX - 2) + 1;
  522.                    y = (int) RANDOM(Y_MAX - 2) + 1;
  523.                   } while (grid[x][y] != EMPTY);
  524.  
  525.                /* Put creature type onto the grid */
  526.                grid[x][y] = c_type;
  527.               }
  528.          }
  529.     }
  530.  
  531.  
  532.  /* Search grid and set up the initial conditions for each creature */
  533.  for (x = 1; x <= X_MAX; x++)
  534.      {
  535.       for (y = 1; y <= Y_MAX; y++)
  536.           {
  537.            if ((c_type = grid[x][y]) != EMPTY)
  538.               {
  539.                id.s.name = type[c_type].name;
  540.                ++number;
  541.                ++pop_tots[c_type];
  542.                ++old_pop_tots[c_type];
  543.  
  544.  
  545.                /* Set up data */
  546.                creature[number].type = c_type;
  547.                creature[number].x    = x;
  548.                creature[number].y    = y;
  549.                creature[number].dx = (signed char) (RANDOM(2)) - 1;
  550.                creature[number].dy = (signed char) (RANDOM(2)) - 1;
  551.                creature[number].str=(int)(1+RANDOM(type[c_type].max_str/2));
  552.                creature[number].move_c=(int) (1 + RANDOM(type[c_type].move));
  553.                creature[number].age = (int) (1 + RANDOM(type[c_type].adult));
  554.  
  555.                /* Draw sprite on the screen */
  556.                #if GRAPHICS == TRUE
  557.                if (global.draw_creatures == TRUE)
  558.                   {
  559.                    sprite_put_given(sprite_bk, &id, 0,
  560.                                     x * SCREEN_X, y * SCREEN_Y);
  561.                   }
  562.                #endif
  563.               }
  564.           }
  565.      }
  566.  
  567.  }
  568.  
  569. /**************************************************************************/
  570. /* Draw graph axes */
  571.  
  572. void draw_axes(void)
  573.  
  574. {
  575.  int        n;
  576.  sprite_id  id;
  577.  
  578.  bbc_gcol(0,GREY1);
  579.  bbc_move(ORIGIN_X,ORIGIN_Y);
  580.  bbc_drawby(0,1000 - ORIGIN_Y);
  581.  bbc_move(ORIGIN_X,ORIGIN_Y);
  582.  bbc_drawby(WIDTH,0);
  583.  
  584.  bbc_colour(GREY2);
  585.  bbc_tab(63,0);
  586.  printf("Iteration");
  587.  bbc_colour(WHITE);
  588.  bbc_tab(64,1);
  589.  printf("Total");
  590.  
  591.  for (n = 1; n <= global.total_types; n++)
  592.      {
  593.       bbc_colour(BLUE + n);
  594.       bbc_tab(64,n + 1);
  595.       printf("%s",type[n].name);
  596.       bbc_tab(73,n + 1);
  597.       printf("%i",pop_tots[n]);
  598.  
  599.       #if GRAPHICS == TRUE
  600.       if (global.draw_creatures == TRUE)
  601.          {
  602.           id.s.name = type[n].name;
  603.           sprite_put_given(sprite_bk, &id, 0, 970,968 - (n * 32));
  604.          }
  605.       #endif
  606.      }
  607. }
  608.  
  609. /**************************************************************************/
  610.  
  611.  
  612.  
  613. /**************************************************************************/
  614. /*                           MAIN PROCESSING                              */
  615. /**************************************************************************/
  616. /* Main processing loop */
  617.  
  618. void main_loop(void)
  619.  
  620. {
  621.  int loop;
  622.  
  623.  for (loop = 1; loop <= global.iterations; loop++)
  624.      {
  625.       process_creatures();
  626.       update_graph(loop);
  627.       srand(clock());
  628.      }
  629.  
  630. }
  631.  
  632. /**************************************************************************/
  633. /* Do one iteration */
  634.  
  635. void process_creatures(void)
  636.  
  637. {
  638.  int   pause;
  639.  int   c;
  640.  int   t;
  641.  
  642.  for (c = 1; c <= MAX_CREATURES; c++)
  643.      {
  644.       if (creature[c].str != DEAD)
  645.          {
  646.           /* Get the type of creature */
  647.           t = creature[c].type;
  648.  
  649.           /* Age the creature */
  650.           ++creature[c].age;
  651.  
  652.           /* Update movement counter */
  653.           if (++creature[c].move_c >= type[t].move && type[t].move != 0)
  654.              { move_creature(c, t); }
  655.  
  656.           /* Check for food */
  657.           feed(c, t);
  658.  
  659.           /* Consume strength */
  660.           consume_strength(c, t);
  661.  
  662.           /* Give birth to child ? */
  663.           birth(c, t);
  664.  
  665.          }
  666.  
  667.       /* Pause */
  668.       for (pause = 0; pause <= (global.wait * 100); pause++) { }
  669.  
  670.      }
  671. }
  672.  
  673. /**************************************************************************/
  674. /* Update the graph */
  675.  
  676. void update_graph(int loop)
  677.  
  678. {
  679.  static int   x = 0;
  680.  static int   old_overall_total = 0;
  681.         int   n;
  682.         int   dead = 0;
  683.         int   overall_total = 0;
  684.  
  685.  
  686.  /* Check for end of graph */
  687.  if (++x >= WIDTH)
  688.     {
  689.      x = 1;
  690.      bbc_gcol(0,BLACK);
  691.      bbc_rectanglefill(ORIGIN_X + 2,ORIGIN_Y + 4,WIDTH,1000 - ORIGIN_Y + 24);
  692.     }
  693.  
  694.  
  695.  /* Print current iteration */
  696.  bbc_colour(GREY2);
  697.  bbc_tab(73,0);
  698.  printf("%i",loop);
  699.  
  700.  
  701.  /* Plot graph and update population totals */
  702.  for (n = 1; n <= global.total_types; n++)
  703.      {
  704.       if (pop_tots[n] > NULL)
  705.          {
  706.           bbc_gcol(0, BLUE + n);
  707.           bbc_move(ORIGIN_X + x - 1, (int)
  708.                    (ORIGIN_Y + 4 + (global.graph_scale * old_pop_tots[n])));
  709.           bbc_draw(ORIGIN_X + x, (int)
  710.                    (ORIGIN_Y + 4 + (global.graph_scale * pop_tots[n])));
  711.          }
  712.          else
  713.          {
  714.           ++dead;
  715.          }
  716.  
  717.       bbc_colour(BLUE + n);
  718.       bbc_tab(73,n + 1);
  719.       printf("%i  ",pop_tots[n]);
  720.  
  721.       overall_total += pop_tots[n];
  722.       old_pop_tots[n] = pop_tots[n];
  723.  
  724.      }
  725.  
  726.  /* Plot overall creature total */
  727.  bbc_colour(WHITE);
  728.  bbc_tab(73,1);
  729.  printf("%i  ",overall_total);
  730.  if (global.draw_overall == TRUE)
  731.     {
  732.      bbc_gcol(0,WHITE);
  733.      bbc_move(ORIGIN_X + x - 1, (int)
  734.               (ORIGIN_Y + 4 + (global.graph_scale * old_overall_total)));
  735.      bbc_draw(ORIGIN_X + x, (int)
  736.               (ORIGIN_Y + 4 + (global.graph_scale * overall_total)));
  737.      old_overall_total = overall_total;
  738.     }
  739.  
  740.  
  741.  /* All creatures dead - end program */
  742.  if (dead == global.total_types)
  743.     {
  744.      bbc_tab(0,29);
  745.      exit(NULL);
  746.     }
  747. }
  748.  
  749. /**************************************************************************/
  750. /* Move a creature */
  751.  
  752. void move_creature(int c_number, int c_type)
  753.  
  754. {
  755.  char       oldx, oldy;
  756.  char       newx, newy;
  757.  sprite_id  id;
  758.  
  759.  
  760.  /* Reset movement counter */
  761.  creature[c_number].move_c = 0;
  762.  
  763.  
  764.  /* Choose new dx and dy ? */
  765.  if ((int) (RANDOM(10)) == 10)
  766.     {
  767.      creature[c_number].dx = (signed char) (RANDOM(2)) - 1;
  768.      creature[c_number].dy = (signed char) (RANDOM(2)) - 1;
  769.     }
  770.  
  771.  
  772.  /* Determine new location */
  773.  oldx = creature[c_number].x;
  774.  oldy = creature[c_number].y;
  775.  newx = oldx + creature[c_number].dx;
  776.  newy = oldy + creature[c_number].dy;
  777.  
  778.  #if WRAP_AROUND == TRUE
  779.  if (newx > X_MAX) { newx = 1;     }
  780.  if (newx == 0)    { newx = X_MAX; }
  781.  if (newy > Y_MAX) { newy = 1;     }
  782.  if (newy == 0)    { newy = Y_MAX; }
  783.  #endif
  784.  
  785.  #if WRAP_AROUND == FALSE
  786.  if (newx > X_MAX) { newx = X_MAX; }
  787.  if (newx == 0)    { newx = 1;     }
  788.  if (newy > Y_MAX) { newy = Y_MAX; }
  789.  if (newy == 0)    { newy = 1;     }
  790.  #endif
  791.  
  792.  /* If the new location is empty then move the creature */
  793.  if (grid[newx][newy] == EMPTY)
  794.     {
  795.      /* Remove creature from old location */
  796.      grid[oldx][oldy] = EMPTY;
  797.      #if GRAPHICS == TRUE
  798.      if (global.draw_creatures == TRUE)
  799.         {
  800.          id.s.name = "blank";
  801.          sprite_put_given(sprite_bk, &id, 0,
  802.                           oldx * SCREEN_X, oldy * SCREEN_Y);
  803.         }
  804.      #endif
  805.  
  806.  
  807.      /* Draw creature in the new location */
  808.      grid[newx][newy] = c_type;
  809.      #if GRAPHICS == TRUE
  810.      if (global.draw_creatures == TRUE)
  811.         {
  812.          id.s.name = type[c_type].name;
  813.          sprite_put_given(sprite_bk, &id, 0,
  814.                           newx * SCREEN_X, newy * SCREEN_Y);
  815.         }
  816.      #endif
  817.  
  818.  
  819.      /* Update the creatures current coordinates */
  820.      creature[c_number].x = newx;
  821.      creature[c_number].y = newy;
  822.     }
  823. }
  824.  
  825. /**************************************************************************/
  826. /* Creature consumes strength */
  827.  
  828. void consume_strength(int c_number, int c_type)
  829.  
  830. {
  831.  int        dir;
  832.  int        decay_number;
  833.  int        decay_type;
  834.  int        x, y;
  835.  int        dx,dy;
  836.  sprite_id  id;
  837.  
  838.  
  839.  /* Consume strength. If the strength falls to zero or less 
  840.   * the kill the creature */
  841.  if ((creature[c_number].str -= type[c_type].consumption) <= 0)
  842.     {
  843.      x = creature[c_number].x;
  844.      y = creature[c_number].y;
  845.  
  846.      /* Kill the creature */
  847.      creature[c_number].str = DEAD;
  848.      --pop_tots[c_type];
  849.      grid[x][y] = EMPTY;
  850.  
  851.      #if GRAPHICS == TRUE
  852.      if (global.draw_creatures == TRUE)
  853.         {
  854.          id.s.name = "blank";
  855.          sprite_put_given(sprite_bk, &id, 0, x * SCREEN_X, y * SCREEN_Y);
  856.         }
  857.      #endif
  858.  
  859.  
  860.      /* Does the death of this creature form any decay products ? */
  861.      decay_type = type[c_type].decay;
  862.      if (decay_type != NULL)
  863.         {
  864.          for (dir = 0; dir < DIRECTIONS; dir++)
  865.              {
  866.               dx = x + loc_offset[dir].dx;
  867.               dy = y + loc_offset[dir].dy;
  868.  
  869.               /* Is the cell location valid ? */
  870.               if (valid_location(dx,dy) == TRUE)
  871.                  {
  872.                   /* Is cell empty ? */
  873.                   if (grid[dx][dy] == EMPTY)
  874.                      {
  875.                       /* Resurrect a dead creature (except if FAIL) */
  876.                       if ((decay_number = find_free_creature()) != FAIL)
  877.                          {
  878.                           /* Create decay creature */
  879.                           creature[decay_number].str = 
  880.                               1 + (int) RANDOM(type[decay_type].max_str);
  881.                           creature[decay_number].age    = 1;
  882.                           creature[decay_number].type   = decay_type;
  883.                           creature[decay_number].move_c = 0;
  884.                           creature[decay_number].x      = dx;
  885.                           creature[decay_number].y      = dy;
  886.                           creature[decay_number].dx =
  887.                               (signed char) (RANDOM(2)) - 1;
  888.                           creature[decay_number].dy =
  889.                               (signed char) (RANDOM(2)) - 1;
  890.                           ++pop_tots[decay_type];
  891.  
  892.  
  893.                           /* Fill grid and draw decay creature on screen */
  894.                           grid[dx][dy] = decay_type;
  895.  
  896.                           #if GRAPHICS == TRUE
  897.                           if (global.draw_creatures == TRUE)
  898.                              {
  899.                               id.s.name = type[decay_type].name;
  900.                               sprite_put_given(sprite_bk, &id, 0,
  901.                                                dx * SCREEN_X, dy * SCREEN_Y);
  902.                              }
  903.                           #endif
  904.                          }
  905.                      }
  906.                  }    
  907.              }
  908.         }
  909.     }
  910. }
  911.  
  912. /**************************************************************************/
  913. /* Check surrounding locations for possible food */
  914.  
  915. void feed(int c_number, int c_type)
  916.  
  917. {
  918.  int        n;
  919.  int        x, y;
  920.  int        dx,dy;
  921.  int        nbour_type;
  922.  int        nbour_number;
  923.  sprite_id  id;
  924.  
  925.  
  926.  x = creature[c_number].x;
  927.  y = creature[c_number].y;
  928.  
  929.  for (n = 0; n < DIRECTIONS; n++)
  930.      {
  931.       dx = x + loc_offset[n].dx;
  932.       dy = y + loc_offset[n].dy;
  933.  
  934.  
  935.       /* Check that the neighbouring cell is on grid */
  936.       if (valid_location(dx,dy) == TRUE)
  937.          {
  938.           /* Get creature type in the cell */
  939.           nbour_type = grid[dx][dy];
  940.           if (nbour_type != EMPTY)
  941.              {
  942.               /* Does this creature eat neighbouring type ? */
  943.               if ((type[c_type].food  &  (int) (pow(2,nbour_type))) != NULL)
  944.                  {
  945.                   /* Find the neighbour's number */
  946.                   if ((nbour_number = find_creature_at(dx,dy)) != FAIL)
  947.                      {
  948.                       /* Eat the neighbour */
  949.                       creature[c_number].str += type[nbour_type].food_value;
  950.                       if (creature[c_number].str > type[c_type].max_str)
  951.                          { creature[c_number].str = type[c_type].max_str; }
  952.                       creature[nbour_number].str = DEAD;
  953.                       --pop_tots[nbour_type];
  954.  
  955.                       /* Remove neighbour from grid and screen */
  956.                       grid[dx][dy] = EMPTY;
  957.  
  958.                       #if GRAPHICS == TRUE
  959.                       if (global.draw_creatures == TRUE)
  960.                          {
  961.                           id.s.name = "blank";
  962.                           sprite_put_given(sprite_bk, &id, 0,
  963.                                            dx * SCREEN_X, dy * SCREEN_Y);
  964.                          }
  965.                       #endif
  966.                      }
  967.                  }
  968.              }
  969.          }
  970.      }
  971.  
  972. }
  973.  
  974. /**************************************************************************/
  975. /* Give birth to a child */
  976.  
  977. void birth(int c_number, int c_type)
  978.  
  979. {
  980.  int        dir;
  981.  int        child_number;
  982.  int        x, y;
  983.  sprite_id  id;
  984.  
  985.  
  986.  /* Can the creature have children and is the creature an adult ? */
  987.  if (type[c_type].adult > 0 && creature[c_number].age >= type[c_type].adult)
  988.     {
  989.      /* Has the creature enough strength ? */
  990.      if (creature[c_number].str >= type[c_type].birth_str)
  991.         {
  992.          /* Choose and random neighbouring cell - check that it is valid */
  993.          dir = (int) RANDOM(DIRECTIONS - 1);
  994.          x = creature[c_number].x + loc_offset[dir].dx;
  995.          y = creature[c_number].y + loc_offset[dir].dy;
  996.          if (valid_location(x,y) == TRUE)
  997.             {
  998.              /* Check that cell is empty */
  999.              if (grid[x][y] == EMPTY)
  1000.                 {
  1001.                  /* Resurrect a dead creature (except if FAIL) */
  1002.                  if ((child_number = find_free_creature()) != FAIL)
  1003.                     {
  1004.                      /* Create child */
  1005.                      creature[child_number].str = creature[c_number].str *
  1006.                                               type[c_type].child_str / 100;
  1007.                      creature[child_number].age    = 1;
  1008.                      creature[child_number].type   = c_type;
  1009.                      creature[child_number].move_c = 0;
  1010.                      creature[child_number].x      = x;
  1011.                      creature[child_number].y      = y;
  1012.                      creature[child_number].dx=(signed char) (RANDOM(2)) - 1;
  1013.                      creature[child_number].dy=(signed char) (RANDOM(2)) - 1;
  1014.                      ++pop_tots[c_type];
  1015.  
  1016.  
  1017.                      /* Adjust parents data */
  1018.                      creature[c_number].str = creature[c_number].str *
  1019.                                   (100 - type[c_type].child_str) / 100;
  1020.  
  1021.  
  1022.                      /* Fill grid and draw child creature on screen */
  1023.                      grid[x][y] = c_type;
  1024.  
  1025.                      #if GRAPHICS == TRUE
  1026.                      if (global.draw_creatures == TRUE)
  1027.                         {
  1028.                          id.s.name = type[c_type].name;
  1029.                          sprite_put_given(sprite_bk, &id, 0,
  1030.                                           x * SCREEN_X, y * SCREEN_Y);
  1031.                         }
  1032.                      #endif
  1033.                     }
  1034.                 }
  1035.             }
  1036.         }
  1037.     }
  1038. }
  1039.  
  1040. /**************************************************************************/
  1041.  
  1042.  
  1043.  
  1044.  
  1045. /**************************************************************************/
  1046. /*                           GENERAL ROUTINES                             */
  1047. /**************************************************************************/
  1048. /* Check that location is valid ie on the grid */
  1049.  
  1050. BOOL valid_location(char x, char y)
  1051.  
  1052. {
  1053.  if (x > X_MAX  ||  x < 1  ||  y > Y_MAX  ||  y < 1) { return(FALSE); }
  1054.  
  1055.  return(TRUE);
  1056. }
  1057.  
  1058. /**************************************************************************/
  1059. /* Find the creature number at a given location or return FAIL
  1060.  * if not found */
  1061.  
  1062. int find_creature_at(char x, char y)
  1063.  
  1064. {
  1065.  int n;
  1066.  
  1067.  for (n = 1; n <= MAX_CREATURES; n++)
  1068.      {
  1069.       if (creature[n].str != DEAD)
  1070.          {
  1071.           if (creature[n].x == x  &&  creature[n].y == y)
  1072.              { return(n); }
  1073.          }
  1074.      }
  1075.  
  1076.  return(FAIL);
  1077. }
  1078.  
  1079. /**************************************************************************/
  1080. /* Return a dead creature for reuse or FAIL if not available */
  1081.  
  1082. int find_free_creature(void)
  1083.  
  1084. {
  1085.  int n;
  1086.  
  1087.  for (n = 1; n <= MAX_CREATURES; n++)
  1088.      {
  1089.       if (creature[n].str == DEAD) { return(n); }
  1090.      }
  1091.  
  1092.  return(FAIL);
  1093.  
  1094. }
  1095.  
  1096. /**************************************************************************/
  1097. /* Main procedure */
  1098.  
  1099. int main()
  1100.  
  1101. {
  1102.  initialise();
  1103.  if (load_file() == FALSE) { return(NULL); }
  1104.  create_populations();
  1105.  draw_axes();
  1106.  main_loop();
  1107.  
  1108.  bbc_tab(0,29);
  1109.  return(NULL);
  1110. }
  1111.  
  1112. /**************************************************************************/
  1113.  
  1114.  
  1115.